MTK feature phone上生成二维码
添加LibQREncode
首先呢,我们在github上可以搜到很多LibQREncode相关的项目,LibQREncode使用C语言编写的二维码编码库 github项目地址:libqrencode
然后我还不小心找到一个QRCODE 生成器的c++代码项目
QRGenerator
那么我接下来的工作就比较简单啦,就将这个C++的二维码生成器移植到feature phone平台上,稍作改良。
生成二维码bmp图片
根据QRGenerator可以很快改造一下,调用libqrencode库生成二维码bmp图片。代码如下:
bitmap图片编码的一些头文件定义:
#define OUT_FILE_PIXEL_PRESCALER 4
#define PIXEL_COLOR_R 0
#define PIXEL_COLOR_G 0
#define PIXEL_COLOR_B 0
//rgb 0 0 0,代表 黑色
#define BI_RGB 0L
#pragma pack(push, 1)
typedef struct
{
U16 bfType;
U32 bfSize;
U16 bfReserved1;
U16 bfReserved2;
U32 bfOffBits;
} BITMAPFILEHEADER;
typedef struct
{
U32 biSize;
S32 biWidth;
S32 biHeight;
U16 biPlanes;
U16 biBitCount;
U32 biCompression;
U32 biSizeImage;
S32 biXPelsPerMeter;
S32 biYPelsPerMeter;
U32 biClrUsed;
U32 biClrImportant;
} BITMAPINFOHEADER;
typedef struct
{
BITMAPFILEHEADER kFileHeader;
BITMAPINFOHEADER kInfoHeader;
unsigned char g_rgb_data[100000];
} BITMAPDATA;
#pragma pack(pop)
实现二维码编码具体代码:
BITMAPDATA bitmapData;//定义一个全局变量,用户存放编码图片信息
// ox要显示的图片的x坐标,Y坐标
// resize_w 调整图片大小
// szSourceString 要转换为二维码的字符串,比如网址啊之类的
int mmi_getQRcode(S32 ox,S32 oy,S32 resize_w, char* szSourceString){
//char* szSourceString = QRCODE_TEXT;
unsigned int unWidth,x,y,l,n,unWidthAdjusted,unDataBytes;
unsigned char* pRGBData,*pSourceData,*pDestData;
QRcode* pQRC;
S32 fd;
S32 fs_ret;
U32 nLen;
S32 w,h,rec_x,rec_y,rec_w;
S32 resize_h=resize_w;
pQRC = QRcode_encodeString(szSourceString,0,QR_ECLEVEL_H,QR_MODE_8,1);
//调用lib库中的函数,获取二维码编码信息。然后接下来的工作都是将获取的这个二维码编码信息转换为图片
unWidth = pQRC->width;
kal_prompt_trace(MOD_MMI,"%d unWidth --linlian .\n",unWidth);
unWidthAdjusted = unWidth * OUT_FILE_PIXEL_PRESCALER * 3;
kal_prompt_trace(MOD_MMI,"%d unWidthAdjusted --linlian .\n",unWidthAdjusted);
if (unWidthAdjusted % 4)
unWidthAdjusted = (unWidthAdjusted / 4 + 1) * 4;
unDataBytes = unWidthAdjusted * unWidth * OUT_FILE_PIXEL_PRESCALER;
kal_prompt_trace(MOD_MMI,"%d unDataBytes --linlian .\n",unDataBytes);
if (unDataBytes > sizeof(bitmapData.g_rgb_data))
{
kal_prompt_trace(MOD_MMI,"%d unDataBytes out of memory --linlian .\n",unDataBytes);
return 0; // out of memory
}
pRGBData = bitmapData.g_rgb_data;
memset(pRGBData, 0xff, unDataBytes);//将所有的点设置为0XFF,则为白色
bitmapData.kFileHeader.bfType = 0x4d42; // "BM"
bitmapData.kFileHeader.bfSize = sizeof(BITMAPFILEHEADER) +
sizeof(BITMAPINFOHEADER) +
unDataBytes;
bitmapData.kFileHeader.bfReserved1 = 0;
bitmapData.kFileHeader.bfReserved2 = 0;
bitmapData.kFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) +
sizeof(BITMAPINFOHEADER);
bitmapData.kInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmapData.kInfoHeader.biWidth = unWidth * OUT_FILE_PIXEL_PRESCALER;
bitmapData.kInfoHeader.biHeight = ((int)unWidth * OUT_FILE_PIXEL_PRESCALER);
bitmapData.kInfoHeader.biPlanes = 1;
bitmapData.kInfoHeader.biBitCount = 24;
bitmapData.kInfoHeader.biCompression = BI_RGB;
bitmapData.kInfoHeader.biSizeImage = 0;
bitmapData.kInfoHeader.biXPelsPerMeter = 0;
bitmapData.kInfoHeader.biYPelsPerMeter = 0;
bitmapData.kInfoHeader.biClrUsed = 0;
bitmapData.kInfoHeader.biClrImportant = 0;
pSourceData = pQRC->data;
qijiReverseData(pSourceData,unWidth);//linlian@2016.03.04 reverse qrcode image vertically
for(y = 0; y < unWidth; y++)
{
pDestData = pRGBData + unWidthAdjusted * y * OUT_FILE_PIXEL_PRESCALER;
for(x = 0; x < unWidth; x++)
{
if (*pSourceData & 1)//在pSourceData数组中值为1的点,将其颜色设置为BGR 000,则对应点变为黑色
{
for(l = 0; l < OUT_FILE_PIXEL_PRESCALER; l++)
{
for(n = 0; n < OUT_FILE_PIXEL_PRESCALER; n++)
{
*(pDestData + n * 3 + unWidthAdjusted * l) = PIXEL_COLOR_B;
*(pDestData + 1 + n * 3 + unWidthAdjusted * l) = PIXEL_COLOR_G;
*(pDestData + 2 + n * 3 + unWidthAdjusted * l) = PIXEL_COLOR_R;
}
}
}
pDestData += 3 * OUT_FILE_PIXEL_PRESCALER;
pSourceData++;
}
}
//前面这段代码的意思是,初始化好bmp图片文件的头部。
//并且在后面追加每个点的颜色定义。最后我们获取了一系列黑白点阵
//OslMfree(pRGBData);
nLen = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+sizeof(unsigned char)*unDataBytes;
gdi_image_get_dimension_mem(GDI_IMAGE_TYPE_BMP,(U8*)&bitmapData,nLen,&w,&h);
kal_prompt_trace(MOD_MMI," %d w --linlian .\n",w);
kal_prompt_trace(MOD_MMI," %d h --linlian .\n",h);
img_width =w;
img_height=h;
if(w < resize_w || resize_w==0){ //can't be larger than original width
resize_w = w;
resize_h = h;
}
if(resize_w>100){
resize_w =100;
resize_h =100;
}
if(ox<=0||oy<=0){
ox=(UI_device_width-resize_w)/2;
oy=(UI_device_height-resize_h)/2+10;
}
kal_prompt_trace(MOD_MMI," %d resize_w --linlian .\n",resize_w);
kal_prompt_trace(MOD_MMI," %d resize_h--linlian .\n",resize_h);
//gdi_image_draw_mem(ox,oy,(U8*)&bitmapData,GDI_IMAGE_TYPE_BMP,nLen);
rec_x = ox-2;
rec_y = oy-2;
rec_w = resize_w +4;
gdi_draw_solid_rect(rec_x,rec_y,rec_x+rec_w,rec_y+rec_w,GDI_COLOR_WHITE);
gdi_image_draw_resized_mem(ox,oy,resize_w,resize_h,(U8*)&bitmapData,GDI_IMAGE_TYPE_BMP,nLen);
preWidth = resize_w;
QRcode_free(pQRC);
return 1;
}
这边要说明一下,在pc平台上,将bitmapData.kInfoHeader.biHeight = -((int)unWidth * OUT_FILE_PIXEL_PRESCALER);
也就是biHeight设置为负值的话,可以实现图片的垂直翻转,但是在feature phone上,如果biHeight直接设置为负值,那么图片将不被识别,所以,我们只能将biHeight设置为+((int)unWidth * OUT_FILE_PIXEL_PRESCALER)
。因此,在原始的0101数据开始被rgb化的时候,我们先将这串数据组成一个二维正方形数组,并进行以中间高度为中心的上下翻转。即qijiReverseData(pSourceData,unWidth);
。对应的代码为
// vertical reverse image
void qijiReverseData(unsigned char* data, unsigned int unWidth){
unsigned int i,j;
unsigned char temp;
for( i=0 ;i<(unWidth/2);i++){
for(j=0;j<unWidth;j++){
temp = data[j+i*unWidth];
data[j+i*unWidth] = data[(unWidth-1-i)*unWidth+j];
data[(unWidth-1-i)*unWidth+j]=temp;
}
}
}
平台适配调整
基本上qrcode lib库的代码在feature phone的模拟器上运行时没有问题的,但是在实际的机子上,需要调整一些内存分配等方法,进行平台适配。例如:
- data = (unsigned char )*malloc(bstream->length + arg->length);
需要改为
data = (unsigned char *)OslMalloc**(bstream->length + arg->length); - free(bstream->data); –> OslMfree(bstream->data);
- raw->rsblock = (RSblock )calloc(raw->blocks, sizeof(RSblock));改为 raw->rsblock = (RSblock )*OslMalloc**((raw->blocks)(sizeof(RSblock)));memset(raw->rsblock, 0x00, (raw->blocks)*(sizeof(RSblock)));
总结
有时候我们都不知道自己是怎么完成这一步步的瞎子摸象。例如我突然想不起来,曾经写过一个给校准树写DLL的经历,我只记得接到任务的时候,只有“懵逼”来形容,什么事校准树,什么事DLL,特么我是写android的,C是什么鬼,我只在大学学过C++。然后,我在万用的路上越走越远。也许有圣人相助,反正每个感觉完不成的任务,最后也都完成了,再见了feature phone~